﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;

namespace DataTransferObject
{
    /*
     * Lưu trữ thông tin chi tiết của 1 task
     */ 
    [Serializable]
    public class Task
    {
        #region Static fields
        public static DateTime UNDEFINED_DUE_DATE = DateTime.MaxValue;
        public static DateTime UNDEFINED_RELEASE_DATE = DateTime.MinValue;
        public static DateTime UNDEFINED_START_ON_OR_AFTER = DateTime.MinValue;
        public static int CurrentID = 0;
        #endregion

        #region Attributes
        private int _taskID;
        private int _index;
        private TaskList _taskList;
        private int projectID;
        private String projectName;
        private int workingHourID;
        private int _minimumTimeSplit;

        private List<int> _predecessorIDs = new List<int>();
        //private List<Task> _predecessorTasks = new List<Task>();

        private int _sucessorID;

        private Double _weight;

        private DateTime _startDate;
        private DateTime _endDate;

        private int _priority;
        private int _totalWork;
        private bool _completed; //complete or incomplete
        private int _remainTime;
        private String _name;

        private String _notes;

        private int _taskStatusIndex;
        private int _taskPercentageCompletedIndex;

        private DateTime _releaseDate = UNDEFINED_RELEASE_DATE;
        private DateTime _dueDate = UNDEFINED_DUE_DATE;
        private DateTime _startOnOrAfter = UNDEFINED_START_ON_OR_AFTER;

        private double _mappedReleaseDate;
        private double _mappedDueDate;
        private double _mappedStartOnOrAfter;
        //_taskcode được dùng để phân biệt hai task với nhau
        private Double _taskCode = -1;
        public const int FIT = 0;
        public const int LARGER = 1;
        public const int SMALLER = -1;
        public const int OUTOF = -2;
        //private List<int> _successorIndices;

        //public static int maxNumberOfTask = 100;
        //public static int maxNumberOfFreeTimeBlock = 100;

        #endregion

        #region Constructors
        public Task()
        {
            this._taskID = CurrentID;
            _taskList = new DataTransferObject.TaskList();
            CurrentID++;
        }

        public Task(Task sourceTask)
        {
            _taskID = sourceTask.TaskID;

            projectID = sourceTask.ProjectID;
            projectName = sourceTask.ProjectName;
            workingHourID = sourceTask.WorkingHourID;
            for (int i = 0; i < sourceTask.PredecessorIDs.Count; i++)
            {
                _predecessorIDs.Add(sourceTask._predecessorIDs[i]);
            }
            _weight = sourceTask.Weight;
            _startDate = sourceTask.ScheduledStartDate;
            _endDate = sourceTask.ScheduledEndDate;
            _priority = sourceTask.Priority;
            _totalWork = sourceTask.TotalWork;
            _completed = sourceTask.Completed;
            _remainTime = sourceTask.RemainTime;
            _name = sourceTask.Name;
            _taskStatusIndex = sourceTask.TaskStatusIndex;
            _taskPercentageCompletedIndex = sourceTask.TaskPercentageCompletedIndex;
            _mappedReleaseDate = sourceTask.MappedReleaseDate;
            _mappedDueDate = sourceTask.MappedDueDate;
        }
        public Task(String name, int priority, int totalWork, TaskList tl)
        {
            this._taskID = CurrentID++;
            this._name = name;
            this._priority = priority;
            this._totalWork = totalWork;
            this._completed = false;
            this._remainTime = totalWork;
            this._taskList = tl;
            this._index = tl.CurrentIndex;
        }

        public Task(String name, int priority, int totalWork)
        {
            this._taskID = CurrentID++;
            this._name = name;
            this._priority = priority;
            this._totalWork = totalWork;
            this._completed = false;
            this._remainTime = totalWork;
        }

        #endregion

        #region Essential Methods

        /// <summary>
        /// Adds the task predecessor. Moreover, set the successor for input task
        /// </summary>
        /// <param name="task">The task.</param>
        public void AddTaskPredecessor(Task task)
        {
            _predecessorIDs.Add(task.TaskID);
            task.SucessorID = this.TaskID;
        }

        public void AddTaskPredecessor(int id)
        {
            _predecessorIDs.Add(id);
            foreach (Task t in TaskList.GetTaskList)
            {
                if (t.TaskID == id)
                {
                    t.SucessorID = this.TaskID;
                }
            }
        }

        public void RemoveTaskPredecessor(Task task)
        {
            for (int i = 0; i < _predecessorIDs.Count; i++)
            {
                if (_predecessorIDs[i] == task.TaskID)
                {
                    _predecessorIDs.RemoveAt(i);
                    return;
                }
            }
        }

        public int CompareWithTimeBlock(FreeTimeBlock freeTimeBlock)
        {
            TimeSpan spanOfFreeBlock = freeTimeBlock.EndDateTime.Subtract(freeTimeBlock.StartDateTime);
            double blockHours = spanOfFreeBlock.TotalHours;
            if (this.TotalWork > blockHours)
            {
                return Task.LARGER;
            }
            else if (this.TotalWork == blockHours)
            {
                return Task.FIT;
            }
            else
            {
                return Task.SMALLER;
            }
        }

        public void UpdateMappedTime(DateTime startScheduleTime)
        {
            // sẽ có trường hợp xảy ra là thời gian bắt đầu schedule (SystemConfiguration.GetStartSchedule()) trễ hơn release date hoặc duedate
            // khi đó ta sẽ gán các MappedTime là bằng -1
            TimeSpan t = _releaseDate.Subtract(startScheduleTime);
            _mappedReleaseDate = t.TotalHours;
            t = _dueDate.Subtract(startScheduleTime);
            _mappedDueDate = t.TotalHours;
        }

        public bool IsHasConstraint()
        {
           return (!_dueDate.Equals(UNDEFINED_DUE_DATE) || !_releaseDate.Equals(UNDEFINED_RELEASE_DATE) || (_predecessorIDs.Count != 0));
            //return (_predecessorIDs.Count != 0);
        }

        public new bool Equals(object obj)
        {
            if (obj.GetType().Name.Equals("Task"))
            {
                return (this.TaskID == (obj as Task).TaskID);
            }
            else
            {
                return false;
            }
        }



        #endregion

        #region Properties

        public int TaskID
        {
            get { return _taskID; }
            set { _taskID = value; }
        }

        public String ProjectName
        {
            get { return projectName; }
            set { projectName = value; }
        }

        public String Notes
        {
            get { return _notes; }
            set { _notes = value; }
        }

        public int ProjectID
        {
            get { return projectID; }
            set { projectID = value; }
        }

        public int WorkingHourID
        {
            get { return workingHourID; }
            set { workingHourID = value; }
        }

        public int MinimumTimeSplit
        {
            get { return _minimumTimeSplit; }
            set { _minimumTimeSplit = value; }
        }

        /// <summary>
        /// Gets or sets the index of Task in TaskList
        /// </summary>
        /// <value>The index.</value>
        public int Inde
        {
            get { return _index; }
            set { _index = value; }
        }

        [XmlIgnore]
        public TaskList TaskList
        {
            get { return _taskList; }
            set { _taskList = value; }
        }

        [XmlIgnore]
        public List<Task> TaskPredecessors
        {
            get 
            {
                List<Task> predecessors = new List<Task>();
                foreach (int id in _predecessorIDs)
                {
                    foreach (Task t in TaskList.GetTaskList)
                    {
                        if (t.TaskID == id)
                        {
                            predecessors.Add(t);
                        }
                    }
                }
                return predecessors;
            }
            set
            {
                List<Task> predecessors = value;
                _predecessorIDs.Clear();
                foreach (Task t in predecessors)
                {
                    _predecessorIDs.Add(t.TaskID);
                }
            }

        }

        public List<int> PredecessorIDs
        {
            get { return _predecessorIDs; }
            set { _predecessorIDs = value; }
        }

        [XmlIgnore]
        public Task Successor
        {
            get 
            {
                foreach (Task t in TaskList.GetTaskList)
                {
                    if (t.TaskID == SucessorID)
                    {
                        return t;
                    }
                }
                return null;
            }
            set 
            {
                SucessorID = value.TaskID;
            }
        }

        public int SucessorID
        {
            get { return _sucessorID; }
            set { _sucessorID = value; }
        }

        /*[XmlIgnore]
        public List<Task> TaskSuccessors
        {
            get
            {
                List<Task> successors = new List<Task>();
                foreach (int i in _successorIndices)
                {
                    successors.Add(_taskList.GetTaskAt(i));
                }
                return successors;
            }
            set
            {
                List<Task> successors = value;
                _successorIndices.Clear();
                foreach (Task t in successors)
                {
                    _successorIndices.Add(t.Index);
                }
            }
        }

        public List<int> SuccessorIndices
        {
            get { return _successorIndices; }
            set { _successorIndices = value; }
        }
        */
        public Double Weight
        {
            get { return _weight; }
            set { _weight = value; }
        }

        public Double TaskCode
        {
            get
            {
                return _taskCode;
            }
            set { _taskCode = value; }
        }
        /// <summary>
        /// Thiết lập và lấy thông tin về Start Date của task. Nếu Start Date là DateTime.MinValue nghĩa là Task chưa được schedule
        /// </summary>
        /// <value>The start date.</value>
        public DateTime ScheduledStartDate
        {
            get { return _startDate; }
            set { _startDate = value; }
        }

        public DateTime ScheduledEndDate
        {
            get { return _endDate; }
            set { _endDate = value; }
        }

        public int Priority
        {
            get { return _priority; }
            set { _priority = value; }
        }

        public int TotalWork
        {
            get { return _totalWork; }
            set { _totalWork = value; }
        }

        public bool Completed
        {
            get { return _completed; }
            set { _completed = value; }
        }

        public String Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public int TaskStatusIndex
        {
            get { return this._taskStatusIndex; }
            set { this._taskStatusIndex = value; }
        }

        public int TaskPercentageCompletedIndex
        {
            get { return this._taskPercentageCompletedIndex; }
            set { this._taskPercentageCompletedIndex = value; }
        }



        public int RemainTime
        {
            get { return _remainTime; }
            set { _remainTime = value; }
        }

        public DateTime DueDate
        {
            get { return _dueDate; }
            set { _dueDate = value; }
        }

        public DateTime StartOnOrAfter
        {
            get { return _startOnOrAfter; }
            set { _startOnOrAfter = value; }
        }
        public DateTime ReleaseDate
        {
            get { return _releaseDate; }
            set { _releaseDate = value; }
        }

        public double MappedReleaseDate
        {
            get { return _mappedReleaseDate; }
            set { _mappedReleaseDate = value; }
        }

        public double MappedDueDate
        {
            get { return _mappedDueDate; }
            set { _mappedDueDate = value; }
        }
        public double MappedStartOnOrAfterDate
        {
            get { return _mappedStartOnOrAfter; }
            set { _mappedStartOnOrAfter = value; }
        }
        #endregion


        #region Override methods
        public override string ToString()
        {
            return this.Name;
        }
        #endregion


    }
}
